// 版权所有2009 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package reflectlite

import (
	"internal/unsafeheader"
	"runtime"
	"unsafe"
)

const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof（uintpttr（0））但理想常量

// 值是Go值的反射接口。
// 
// 并非所有方法都适用于所有类型的值。每种方法的文档中都注明了限制条件
// 如有。
// 在调用特定于种类的方法之前，请使用Kind方法查找值的种类。调用方法
// 不适合该类型会导致运行时死机。
// 
// 零值表示没有值。
// 其IsValid方法返回false，其Kind方法返回Invalid，
// 其String方法返回“<Invalid Value>”，所有其他方法返回。
// 大多数函数和方法从不返回无效值。
// 如果有，其文档将明确说明条件。
// 
// 如果
// 基础Go值可同时用于等效的
// 直接操作，则一个值可由多个goroutine同时使用。要比较两个值，请比较接口方法的结果。
// 在两个值上使用==不会比较它们所表示的基础值
// 。
type Value struct {
	// typ保存由值表示的值的类型。
	typ *rtype

	// 指针值数据，如果设置了flagIndir，则为指向数据的指针。
	// 当设置了flagIndir或typ.pointers（）为true时有效。
	ptr unsafe.Pointer

	// 标志保存有关该值的元数据。
	// 最低位为标志位：
	// /-flagStickyRO:通过未报告的非嵌入字段获取，因此只读
	// /-Flagmedro:通过未报告的嵌入字段获取，因此，只读
	// /-flagIndir:val持有指向数据的指针
	// /-flagAddr:v.CanAddr为true（意味着flagIndir）
	// Value不能表示方法值。
	// 接下来的五位给出了值的类型。
	// 除了方法值之外，它会重复typ.Kind（）。
	// 剩余的23+位为方法值提供方法编号。
	// If flag.kind（）！=Func，代码可以假定flagMethod未设置。
	// 如果ifaceIndir（类型），则代码可以假定已设置flagIndir。
	flag

	// 方法值表示当前的方法调用。typ+val+标志位描述接收器r中的
	// 但标志的种类位表示Func（方法是
	// 函数），标志的顶部位表示r类型的方法表中的方法编号
	// 。
}

type flag uintptr

const (
	flagKindWidth        = 5 // 共有27种
	flagKindMask    flag = 1<<flagKindWidth - 1
	flagStickyRO    flag = 1 << 5
	flagEmbedRO     flag = 1 << 6
	flagIndir       flag = 1 << 7
	flagAddr        flag = 1 << 8
	flagMethod      flag = 1 << 9
	flagMethodShift      = 10
	flagRO          flag = flagStickyRO | flagEmbedRO
)

func (f flag) kind() Kind {
	return Kind(f & flagKindMask)
}

func (f flag) ro() flag {
	if f&flagRO != 0 {
		return flagStickyRO
	}
	return 0
}

// 指针返回以v表示的底层指针。
// v.Kind（）必须是Ptr、Map、Chan、Func或UnsafePointer 
func (v Value) pointer() unsafe.Pointer {
	if v.typ.size != ptrSize || !v.typ.pointers() {
		panic("can't call pointer on a non-pointer Value")
	}
	if v.flag&flagIndir != 0 {
		return *(*unsafe.Pointer)(v.ptr)
	}
	return v.ptr
}

// packEface将v转换为空接口。
func packEface(v Value) interface{} {
	t := v.typ
	var i interface{}
	e := (*emptyInterface)(unsafe.Pointer(&i))
	// 首先填写接口的数据部分。
	switch {
	case ifaceIndir(t):
		if v.flag&flagIndir == 0 {
			panic("bad indir")
		}
		// 值是间接的，我们正在创建的接口也是间接的。
		ptr := v.ptr
		if v.flag&flagAddr != 0 {
			// TODO:从valueInterface传递安全布尔值，因此
			// 如果safe==true，我们不需要复制？
			c := unsafe_New(t)
			typedmemmove(t, c, ptr)
			ptr = c
		}
		e.word = ptr
	case v.flag&flagIndir != 0:
		// 值是间接的，但接口是直接的。我们需要
		// 将v.ptr上的数据加载到接口数据字中。
		e.word = *(*unsafe.Pointer)(v.ptr)
	default:
		// 值是直接的，接口也是直接的。
		e.word = v.ptr
	}
	// 现在，填写类型部分。我们在这里非常小心，不要在e.word和e.typ赋值之间进行任何操作，这会让垃圾收集器观察部分构建的
	// 接口值。
	e.typ = t
	return i
}

// Unpreface将空接口i转换为值。
func unpackEface(i interface{}) Value {
	e := (*emptyInterface)(unsafe.Pointer(&i))
	// 注意：在我们知道e.word是否真的是指针之前，不要阅读它。
	t := e.typ
	if t == nil {
		return Value{}
	}
	f := flag(t.Kind())
	if ifaceIndir(t) {
		f |= flagIndir
	}
	return Value{t, e.word, f}
}

// 在
// 不支持Value方法的值上调用Value方法时，会发生Value错误。在每种方法的描述中，都记录了此类案例。
type ValueError struct {
	Method string
	Kind   Kind
}

func (e *ValueError) Error() string {
	if e.Kind == 0 {
		return "reflect: call of " + e.Method + " on zero Value"
	}
	return "reflect: call of " + e.Method + " on " + e.Kind.String() + " Value"
}

// methodName返回调用方法的名称，
// 假设为上面的两个堆栈帧。
func methodName() string {
	pc, _, _, _ := runtime.Caller(2)
	f := runtime.FuncForPC(pc)
	if f == nil {
		return "unknown method"
	}
	return f.Name()
}

// emptyInterface是接口{}值的头。
type emptyInterface struct {
	typ  *rtype
	word unsafe.Pointer
}

// 如果f记录值是使用
// 未报告的字段获得的，则必须导出恐慌。
func (f flag) mustBeExported() {
	if f == 0 {
		panic(&ValueError{methodName(), 0})
	}
	if f&flagRO != 0 {
		panic("reflect: " + methodName() + " using value obtained using unexported field")
	}
}

// 如果f记录该值不可赋值，则必须为可分配的恐慌，也就是说，它是使用未报告的字段
// 或者它不可寻址。
func (f flag) mustBeAssignable() {
	if f == 0 {
		panic(&ValueError{methodName(), Invalid})
	}
	// 可寻址且非只读时可分配。
	if f&flagRO != 0 {
		panic("reflect: " + methodName() + " using value obtained using unexported field")
	}
	if f&flagAddr == 0 {
		panic("reflect: " + methodName() + " using unaddressable value")
	}
}

// CanSet报告v的值是否可以更改。
// 仅当值可寻址且不是通过使用未报告的结构字段获得的
// 时，才可以更改该值。
// 如果CanSet返回false，则调用Set或任何特定于类型的
// setter（例如SetBool、SetInt）将死机。
func (v Value) CanSet() bool {
	return v.flag&(flagAddr|flagRO) == flagAddr
}

// Elem返回接口v包含的值或指针v指向的值。
// 如果v的种类不是接口或Ptr，它会感到恐慌。
// 如果v为零，则返回零值。
func (v Value) Elem() Value {
	k := v.kind()
	switch k {
	case Interface:
		var eface interface{}
		if v.typ.NumMethod() == 0 {
			eface = *(*interface{})(v.ptr)
		} else {
			eface = (interface{})(*(*interface {
				M()
			})(v.ptr))
		}
		x := unpackEface(eface)
		if x.flag != 0 {
			x.flag |= v.flag.ro()
		}
		return x
	case Ptr:
		ptr := v.ptr
		if v.flag&flagIndir != 0 {
			ptr = *(*unsafe.Pointer)(ptr)
		}
		// 返回值的地址是v的值。
		if ptr == nil {
			return Value{}
		}
		tt := (*ptrType)(unsafe.Pointer(v.typ))
		typ := tt.elem
		fl := v.flag&flagRO | flagIndir | flagAddr
		fl |= flag(typ.Kind())
		return Value{typ, ptr, fl}
	}
	panic(&ValueError{"reflectlite.Value.Elem", v.kind()})
}

func valueInterface(v Value) interface{} {
	if v.flag == 0 {
		panic(&ValueError{"reflectlite.Value.Interface", 0})
	}

	if v.kind() == Interface {
		// 特殊情况：返回接口内的元素。
		// 空接口有一个布局，所有带有
		// 方法的接口都有第二个布局。
		if v.numMethod() == 0 {
			return *(*interface{})(v.ptr)
		}
		return *(*interface {
			M()
		})(v.ptr)
	}

	// TODO:将safe传递给packEface以便在safe==true时不需要复制？
	return packEface(v)
}

// IsNil报告其参数v是否为零。参数必须是
// 一个chan、func、interface、map、pointer或slice值；如果是
// 不是，那么就没有恐慌。请注意，IsNil并不总是等同于
// 在Go中与nil进行常规比较。例如，如果通过使用未初始化的接口变量i调用ValueOf来创建v，则
// i==nil将为真，但v.IsNil将死机，因为v将是零
// 值。
func (v Value) IsNil() bool {
	k := v.kind()
	switch k {
	case Chan, Func, Map, Ptr, UnsafePointer:
		// 如果v.flag和flagMethod！=0{
		// 返回false 
		// /}
		ptr := v.ptr
		if v.flag&flagIndir != 0 {
			ptr = *(*unsafe.Pointer)(ptr)
		}
		return ptr == nil
	case Interface, Slice:
		// 如果第一个字为0，则接口和片都为零。
		// 两者都比一个词大；假设flagIndir。
		return *(*unsafe.Pointer)(v.ptr) == nil
	}
	panic(&ValueError{"reflectlite.Value.IsNil", v.kind()})
}

// 报告v是否表示值是有效的。
// 如果v为零值，则返回false。
// 如果IsValid返回false，则返回除字符串panic之外的所有其他方法。
// 大多数函数和方法从不返回无效值。
// 如果有，其文档将明确说明条件。
func (v Value) IsValid() bool {
	return v.flag != 0
}

// Kind返回v的种类。
// 如果v为零值（IsValid返回false），则Kind返回无效。
func (v Value) Kind() Kind {
	return v.kind()
}

// 在运行时实现：
func chanlen(unsafe.Pointer) int
func maplen(unsafe.Pointer) int

// Len返回v的长度。
// 如果v的种类不是数组、Chan、Map、Slice或String，它就会恐慌。
func (v Value) Len() int {
	k := v.kind()
	switch k {
	case Array:
		tt := (*arrayType)(unsafe.Pointer(v.typ))
		return int(tt.len)
	case Chan:
		return chanlen(v.pointer())
	case Map:
		return maplen(v.pointer())
	case Slice:
		// 切片比一个单词大；假设flagIndir。
		return (*unsafeheader.Slice)(v.ptr).Len
	case String:
		// 字符串大于一个单词；假设flagIndir。
		return (*unsafeheader.String)(v.ptr).Len
	}
	panic(&ValueError{"reflect.Value.Len", v.kind()})
}

// NumMethod返回值的方法集中导出的方法数。
func (v Value) numMethod() int {
	if v.typ == nil {
		panic(&ValueError{"reflectlite.Value.NumMethod", Invalid})
	}
	return v.typ.NumMethod()
}

// Set将x赋值给值v。
// 如果CanSet返回false，它会恐慌。
// 在Go中，x的值必须可分配给v的类型。
func (v Value) Set(x Value) {
	v.mustBeAssignable()
	x.mustBeExported() // 不要让未报告的x泄漏
	var target unsafe.Pointer
	if v.kind() == Interface {
		target = v.ptr
	}
	x = x.assignTo("reflectlite.Set", v.typ, target)
	if x.flag&flagIndir != 0 {
		typedmemmove(v.typ, v.ptr, x.ptr)
	} else {
		*(*unsafe.Pointer)(v.ptr) = x.ptr
	}
}

// Type返回v的类型。
func (v Value) Type() Type {
	f := v.flag
	if f == 0 {
		panic(&ValueError{"reflectlite.Value.Type", Invalid})
	}
	// 不支持方法值。
	return v.typ
}

/*
 * constructors
 */

// 在包运行时实现
func unsafe_New(*rtype) unsafe.Pointer

// ValueOf返回一个初始化为接口i中存储的具体值
// 的新值。ValueOf（nil）返回零值。
func ValueOf(i interface{}) Value {
	if i == nil {
		return Value{}
	}

	// TODO:可能允许值的内容存在于堆栈上。
	// 现在我们让内容总是转义到堆中。它使一些地方的生活变得更轻松（参见下面的chanrecv/mapsassign-
	// 注释）。
	escapes(i)

	return unpackEface(i)
}

// assignTo返回一个值v，该值可以直接分配给typ。
// 如果v不可分配给typ，则会导致恐慌。
// 对于到接口类型的转换，目标是建议使用的暂存空间。
func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value {
	// 如果v.flag和flagMethod！=0{
	// /v=makeMethodValue（context，v）
	// }

	switch {
	case directlyAssignable(dst, v.typ):
		// /覆盖类型，以便它们匹配。
		// 相同的内存布局，因此不会造成任何伤害。
		fl := v.flag&(flagAddr|flagIndir) | v.flag.ro()
		fl |= flag(dst.Kind())
		return Value{dst, v.ptr, fl}

	case implements(dst, v.typ):
		if target == nil {
			target = unsafe_New(dst)
		}
		if v.Kind() == Interface && v.IsNil() {
			// 将nil ReadWriter传递给nil Reader是可以的，
			// 但是使用下面的ifaceE2I会引起恐慌。
			// 通过显式返回nil dst（如读卡器）避免恐慌。
			return Value{dst, nil, flag(Interface)}
		}
		x := valueInterface(v)
		if dst.NumMethod() == 0 {
			*(*interface{})(target) = x
		} else {
			ifaceE2I(dst, x, target)
		}
		return Value{dst, target, flagIndir | flag(Interface)}
	}

	// 失败。
	panic(context + ": value of type " + v.typ.String() + " is not assignable to type " + dst.String())
}

// arrayAt返回p的第i个元素，
// 一个元素为字节宽的数组。
// p指向的数组必须至少有i+1个元素：
// 传递i>=len，
// 是无效的（但此处无法检查），因为这样结果将指向数组外部。
// 为什么安全必须解释为什么我<len。（传递“i<len”是可以的；
// 好处是在调用站点显示此假设。）
func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer {
	return add(p, uintptr(i)*eltSize, "i < len")
}

func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)

// typedmemmove将类型t的值从src复制到dst。
// go:noescape 
func typedmemmove(t *rtype, dst, src unsafe.Pointer)

// 标记x值转义的伪注释，
// 用于反射代码过于巧妙以致编译器无法遵循
// 的情况。
func escapes(x interface{}) {
	if dummy.b {
		dummy.x = x
	}
}

var dummy struct {
	b bool
	x interface{}
}
